/*
 * Copyright 2009-2010 the original author or authors.
 *
 * Licensed under the Apache license, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.internna.iwebjtracker.project.model;

import java.util.Collection;
import java.util.Date;
import org.internna.iwebjtracker.project.validation.Errors;
import org.internna.iwebjtracker.server.connection.ConnectionDetails;

/**
 * Represents a project in the system.
 *
 * @author Jose Noheda
 * @since 1.0
 */
public interface Project<C extends ConnectionDetails, M extends Module<P, M>, V extends Version<U, P, V>, U extends IWebJTrackerUser, P extends Project<C, M, V, U, P>> {

    /**
     * Valid project types. For now: Frre form and maven.
     */
    enum ProjectType {
        Maven, FreeForm;
    }

    /**
     * Obtain the server configuration for this project.
     *
     * @return a non null object.
     */
    C getConnectionDetails();

    /**
     * Establish the connection details for this project.
     *
     * @param connectionDetails any
     */
    void setConnectionDetails(C connectionDetails);

    /**
     * Absolute URL (relative to repository URL) for this project.
     *
     * @return a not empty String usually starting with "/"
     */
    String getRootPath();

    /**
     * Returns an URL that some server can understand.
     *
     * @return a not empty string
     */
    String getSourceControlURL();

    /**
     * What server type was this project configured for?
     */
    String getServerType();

    /**
     * Returns a type of project
     */
     ProjectType getProjectType();

     /**
      * Stores maven specific information.
      *
      * @param groupId
      * @param artifactId
      */
     void setMavenInfo(String groupId, String artifactId);

     /**
      * Project identifier ideally with some sense for humans.
      *
      * @return a not null/not empty string
      */
     String getProjectName();

     /**
      * Sets the project name.
      *
      * @param name a non empty String
      */
     void setProjectName(String name);

     /**
      * The current development version.
      *
      * @return a not null/not empty string
      */
     V getCurrentVersion();

     /**
      * Set of versions currently defined for this project.
      *
      * @return a not empty collection of versions
      */
     Collection<V> getAllVersions();

     /**
      * Searches the collection of versions looking for one with a particular identifier.
      *
      * @param name any
      * @return any
      */
     V getVersionByName(String name);

     /**
      * Creates a new version and adds it to this project. Optionally include a tentative end date.
      */
     V createVersion(String version, Date due);

     /**
      * The official internet home page for this project that users can visit.
      *
      * @return a not null/not empty string
      */
     String getHomePage();

     /**
      * Sets the project official home page URL.
      */
     void setHomePage(String homePage);

     /**
      * Returns a group of Modules this project owns.
      *
      * @return a non empty unmodifiable collection
      */
     Collection<M> getModules();

     /**
      * Adds a new module to the group of owned modules.
      *
      * @return the added module
      */
     M addModule(M module);

     /**
      * Creates a new module with the provided name and description and adds it to this project.
      *
      * @param moduleName a not empty string
      * @param moduleDescription a not empty string
      * @return the created module
      */
     M createModule(String moduleName, String moduleDescription);

     /**
      * Establish a new alias for this project.
      *
      * @param alias any
      */
     void setAlias(String alias);

     /**
      * Establish a new description for the project
      *
      * @param description
      */
     void setDescription(String description);

     /**
      * Toggles public attribute. A public project is visible to all users (even unauthenticated). A private
      * project is only visible to its developers.
      *
      * @param publicView any
      */
     void setAsPublic(boolean publicView);

     /**
      * Obtain all project administrators.
      *
      * @return a not empty collection
      */
     Collection<U> getProjectAdministrators();

     /**
      * Obtain all project developers that are not administrators.
      *
      * @return a not empty collection
      */
     Collection<U> getProjectDevelopers();

     /**
      * Checks if a user has developer rights.
      *
      * @param user any
      * @return true if the user is a member of this project with developer role
      */
     boolean isDeveloper(U user);

     /**
      * Check if a user has administrator rights.
      *
      * @param user any
      * @return false unless the user has admin role.
      */
     boolean isAdministrator(U user);

     /**
      * Obtain all project administrators and developers.
      *
      * @return a not empty collection
      */
     Collection<U> getProjectMembers();

     /**
      * Adds a new developer to the project that optionally can be also an administrator.
      *
      * @param user any
      * @param asAdministrator false for developers without admin privileges over this entity
      * @return true if the project now has a new member
      */
     boolean addMember(U user, boolean asAdministrator);

     /**
      * Clears the current flag for any version other than the provided one as long
      * as the provided one is a valid (first level) version of the project.
      *
      * @param version any
      * @return true if the provided version has the current flag set to true
      */
     boolean setAsCurrentVersion(V version);

     /**
      * Add this project to the group of projects of interest to this user.
      *
      * @param user any
      * @return true if the user has become an observer in this project
      */
     boolean join(U user);

     /**
      * Checks if this project is closed (no new issues or activity in it)
      *
      * @return false unless the project has been closed
      */
     boolean isClosed();

     /**
      * Closes the project disallowing activity from now on.
      *
      * @param user any
      * @return null if the project was closed successfully, otherwise the problem
      */
     Errors close(U user);

     /**
      * Reopens a previously closed project.
      *
      * @param user any
      * @return null if the project was opened successfully, otherwise the problem
      */
     Errors reopen(U user);

}
